package services

import (
	"bytes"
	"encoding/json"
	"fmt"
	"go.uber.org/zap"
	"io"
	"net/http"
	"neutron_probe/auto"
	. "neutron_probe/models/yAnalyser"
	. "neutron_probe/utils"
)

/*
*
调度服务调用链,把优先级不同的调度服务用责任链的方式链接起来。
排在前面的优先级高,如果前面的拒绝处理则调用后面的
*/
type DataSourceClient struct {
	Origin        string
	LocalOrRemote int // 0:本地,1:远程
}

func (this *DataSourceClient) updateData(funcName string, params interface{}) error {
	if this.LocalOrRemote == 1 {
		return this.updateDataViaRemote(funcName, params)
	} else {
		return this.updateDataViaLocal(params)
	}

}
func (this *DataSourceClient) updateDataViaLocal(params interface{}) error {
	p, ok := params.(*YAnalyser)
	if !ok {
		return fmt.Errorf("invalid params type, expected *YAnalyser")
	}

	//if token is existed,then exit.
	var result []YAnalyser

	db := GetDb().Where(YAnalyser{
		Token: p.Token,
	}).Find(&result)
	if db.Error != nil {
		Logger.Error("Failed to update data", zap.Error(db.Error))
		return db.Error
	}
	if len(result) > 0 {
		Logger.Info("Data is existed!")
		return nil
	}
	// 使用命名占位符的SQL语句
	sql := `INSERT INTO y_analyser (token, analyser_num, crushing_plant, flux,load, mat1, mat10, mat11, mat12, mat13,mat14, mat15, mat16, mat2, mat3, mat4,mat5, mat6, mat7, mat8, mat9, speed,status, test_at) VALUES ('%s','%s','%s',%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%d,%d)`
	realSql := fmt.Sprintf(sql, nullStrAsEmpty(p.Token), nullStrAsEmpty(p.AnalyserNum), nullStrAsEmpty(p.CrushingPlant),
		nullFloat64StrAsNil(p.Flux), nullFloat64StrAsNil(p.Load), nullFloat64StrAsNil(p.Mat1), nullFloat64StrAsNil(p.Mat10),
		nullFloat64StrAsNil(p.Mat11), nullFloat64StrAsNil(p.Mat12), nullFloat64StrAsNil(p.Mat13), nullFloat64StrAsNil(p.Mat14),
		nullFloat64StrAsNil(p.Mat15), nullFloat64StrAsNil(p.Mat16), nullFloat64StrAsNil(p.Mat2), nullFloat64StrAsNil(p.Mat3),
		nullFloat64StrAsNil(p.Mat4), nullFloat64StrAsNil(p.Mat5), nullFloat64StrAsNil(p.Mat6), nullFloat64StrAsNil(p.Mat7),
		nullFloat64StrAsNil(p.Mat8), nullFloat64StrAsNil(p.Mat9), nullFloat64StrAsNil(p.Speed), nullIntStrAsNil(p.Status),
		nullIntStrAsNil(p.TestAt))
	db = GetDb().Exec(realSql)
	return db.Error
}

func nullStrAsEmpty(valuePtr *string) string {
	if valuePtr == nil {
		return ""
	}
	return *valuePtr
}
func nullFloat64StrAsNil(valuePtr *float64) float64 {
	if valuePtr == nil {
		return 0
	}
	return *valuePtr
}
func nullIntStrAsNil(valuePtr *int) int {
	if valuePtr == nil {
		return 0
	}
	return *valuePtr
}

func (this *DataSourceClient) updateDataViaRemote(funcName string, params interface{}) error {
	// 创建请求
	body := map[string]interface{}{
		"sql":        fmt.Sprintf("@%s", funcName),
		"dataSource": "default",
		"params":     params,
	}
	jsonData, err := json.Marshal(body)
	if err != nil {
		return err
	}
	req, err := http.NewRequest("POST", fmt.Sprintf("%s/"+FREE_UPDATE_SQL_WITH_PARAMS, this.Origin), bytes.NewBuffer(jsonData))
	if err != nil {
		return err
	}

	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0")

	// 发送请求
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("error sending request: %w", err)
	}
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("error reading response body: %w", err)
	}
	res := make(map[string]interface{})
	if err = json.Unmarshal(bodyBytes, &res); err != nil {
		return fmt.Errorf("error parse response", err)
	}
	bodyString := string(bodyBytes)
	if res["code"] == nil {
		Logger.Info("fetchDataFromDevice", zap.String("resp", bodyString))
		return fmt.Errorf("error parse response,no code")
	}
	var code = (int)(res["code"].(float64))
	if code != 0 {
		if res["err"] != nil {
			errInfo := res["err"].(string)
			return fmt.Errorf("error update data,code:%d,msg:%s", code, errInfo)
		}
		return fmt.Errorf("error update data,code:%d", code)
	}
	Logger.Info("fetchDataFromDevice", zap.String("resp", bodyString), zap.Int("code", code))
	return nil
	//if res, err := this.ExtractCodeAndMsg(bodyString); err == nil {
	//	Logger.Info("update ok", zap.String("res", Obj2JsonTxt(res)))
	//	return nil
	//} else {
	//	return err
	//}
}

// ExtractAndConvertKeyValuePairs 从XML内容中提取键值对，并将"DataTime"转换为UTC Unix时间戳
func (this *DataSourceClient) ExtractCodeAndMsg(content string) (map[string]interface{}, error) {
	res := map[string]interface{}{}
	err := json.Unmarshal([]byte(content), &res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

var dataSourceClient *DataSourceClient

func GetDataSourceClient() *DataSourceClient {
	return dataSourceClient
}
func StartDataSourceClient(varNamePrex string) bool {
	dataSourceClient = &DataSourceClient{}
	dataSourceClient.LocalOrRemote = GetConfig().Int(varNamePrex+".localOrRemote", 1)
	if dataSourceClient.LocalOrRemote == 1 {
		if dataSourceClient.Origin = GetConfig().String(varNamePrex+".origin", "http://127.0.0.1:7788"); len(dataSourceClient.Origin) == 0 {
			Logger.Error("Failed to Start device of dongFangMeasurement&Control,for the param url empty!")
			dataSourceClient = nil
			return false
		}
	} else if dataSourceClient.LocalOrRemote == 0 {
		ConnectDB("dsn", "dbDriverName")
		AutoMigrate("autoMigrate", auto.AutoMigrateDbList)
	} else {
		Logger.Error("Failed to Start device of dongFangMeasurement&Control,for the param localOrRemote error!")
	}
	return true
}
